package com.ht.config.dataAuth;

import cn.hutool.core.collection.CollectionUtil;
import com.ht.module.sys.service.SysRoleAuthService;
import com.ht.module.sys.vo.SysRoleAuth.UserAuthVo;
import com.ht.util.UserUtil;
import lombok.SneakyThrows;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Properties;

@Intercepts({
        @Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
@Component
public class DataPermissionInterceptor implements Interceptor {

    @Autowired
    private ApplicationContext applicationContext;

    @Override
    @SneakyThrows
    public Object intercept(Invocation invocation) {
        StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
        MetaObject metaObject = SystemMetaObject.forObject(statementHandler);

        // 解代理
        while (metaObject.hasGetter("h")) {
            Object obj = metaObject.getValue("h");
            metaObject = SystemMetaObject.forObject(obj);
        }

        MappedStatement mappedStatement = (MappedStatement) metaObject.getValue("delegate.mappedStatement");
        if (mappedStatement.getSqlCommandType() != SqlCommandType.SELECT) {
            return invocation.proceed();
        }

        BoundSql boundSql = (BoundSql) metaObject.getValue("delegate.boundSql");
        Object parameterObject = boundSql.getParameterObject();
        DataScope dataScope = findDataScopeObject(parameterObject);
        if (dataScope == null) {
            return invocation.proceed();
        }

        String originalSql = boundSql.getSql().trim();
        String lowerSql = originalSql.toLowerCase();

        // 跳过 count 查询
        if (lowerSql.startsWith("select count")) {
            return invocation.proceed();
        }

        // 获取权限数据
        SysRoleAuthService sysRoleAuthService = applicationContext.getBean(SysRoleAuthService.class);
        UserAuthVo authVo = sysRoleAuthService.findByUserId(UserUtil.getUserId());

        List<String> deptIds = new ArrayList<>(authVo.getDeptIds());
        List<String> userIds = new ArrayList<>(authVo.getUserIds());

        if (CollectionUtil.isEmpty(deptIds) && CollectionUtil.isEmpty(userIds)) {
            // 无权限，强制空结果
            metaObject.setValue("delegate.boundSql.sql", "SELECT * FROM (" + originalSql + ") t WHERE 1 = 0");
            return invocation.proceed();
        }

        // 构建权限 SQL
        StringBuilder permissionCondition = new StringBuilder();
        boolean hasCondition = false;
        if (CollectionUtil.isNotEmpty(deptIds)) {
            permissionCondition.append(dataScope.getScopeName())
                    .append(" IN ('").append(CollectionUtil.join(deptIds, "','")).append("')");
            hasCondition = true;
        }
        if (CollectionUtil.isNotEmpty(userIds)) {
            if (hasCondition) {
                permissionCondition.append(" OR ");
            }
            permissionCondition.append(dataScope.getScopeUser())
                    .append(" IN ('").append(CollectionUtil.join(userIds, "','")).append("')");
        }

        // 注入权限 SQL 到原始 SQL 的 WHERE 前
        StringBuilder newSql = new StringBuilder();
        int whereIndex = lowerSql.indexOf(" where ");
        int orderByIndex = lowerSql.indexOf(" order by ");
        int limitIndex = lowerSql.indexOf(" limit ");

        int insertPos = originalSql.length(); // 默认插到末尾
        if (orderByIndex > 0) {
            insertPos = orderByIndex;
        } else if (limitIndex > 0) {
            insertPos = limitIndex;
        }

        if (whereIndex >= 0 && whereIndex < insertPos) {
            // 原 SQL 已有 WHERE，在后面加 AND (...)
            newSql.append(originalSql, 0, insertPos);
            newSql.append(" AND (").append(permissionCondition).append(") ");
            newSql.append(originalSql.substring(insertPos));
        } else {
            // 没有 WHERE，添加 WHERE (...)
            newSql.append(originalSql, 0, insertPos);
            newSql.append(" WHERE (").append(permissionCondition).append(") ");
            newSql.append(originalSql.substring(insertPos));
        }
        // 注入最终 SQL
        metaObject.setValue("delegate.boundSql.sql", newSql.toString());
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return (target instanceof StatementHandler) ? Plugin.wrap(target, this) : target;
    }

    @Override
    public void setProperties(Properties properties) {
        // 可扩展配置
    }

    /**
     * 查找参数中的 DataScope 对象
     */
    private DataScope findDataScopeObject(Object parameterObj) {
        if (parameterObj instanceof DataScope) {
            return (DataScope) parameterObj;
        } else if (parameterObj instanceof Map) {
            for (Object val : ((Map<?, ?>) parameterObj).values()) {
                if (val instanceof DataScope) {
                    return (DataScope) val;
                }
            }
        }
        return null;
    }
}
